{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 2, Topic 2: Introduction to Voltage Glitching (MAIN)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "NOTE: This lab references some (commercial) training material on [ChipWhisperer.io](https://www.ChipWhisperer.io). You can freely execute and use the lab per the open-source license (including using it in your own courses if you distribute similarly), but you must maintain notice about this source location. Consider joining our training course to enjoy the full experience.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**SUMMARY:** *While it's not as sophisticated as the ChipWhisperer Lite or ChipWhisperer Pro's glitch hardware, the ChipWhisperer Nano is also capable of glitching. In this lab, we'll do some simple glitch tests on the Nano's target board, showing how to scan through glitch settings and seeing what effect it has on the hardware.*\n",
    "\n",
    "**LEARNING OUTCOMES:**\n",
    "\n",
    "* Understanding how voltage glitching can be used to disrupt a target's operation\n",
    "* Scanning glitch settings to determine successful ones"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Digital hardware devices have certain voltage and clock requirements to function properly. If these requirements are not met, the device can fail to function, or even be damage. By shorting the voltage pins of a microcontroller for controlled, short periods of time, we can cause it to behave erratically, clearning registers and skipping instructions.  Such attacks can be immensely powerful in practice. Consider for example the following code from `linux-util-2.24`:\n",
    "\n",
    "```C\n",
    "/*\n",
    " *   auth.c -- PAM authorization code, common between chsh and chfn\n",
    " *   (c) 2012 by Cody Maloney <cmaloney@theoreticalchaos.com>\n",
    " *\n",
    " *   this program is free software.  you can redistribute it and\n",
    " *   modify it under the terms of the gnu general public license.\n",
    " *   there is no warranty.\n",
    " *\n",
    " */\n",
    "\n",
    "#include \"auth.h\"\n",
    "#include \"pamfail.h\"\n",
    "\n",
    "int auth_pam(const char *service_name, uid_t uid, const char *username)\n",
    "{\n",
    "    if (uid != 0) {\n",
    "        pam_handle_t *pamh = NULL;\n",
    "        struct pam_conv conv = { misc_conv, NULL };\n",
    "        int retcode;\n",
    "\n",
    "        retcode = pam_start(service_name, username, &conv, &pamh);\n",
    "        if (pam_fail_check(pamh, retcode))\n",
    "            return FALSE;\n",
    "\n",
    "        retcode = pam_authenticate(pamh, 0);\n",
    "        if (pam_fail_check(pamh, retcode))\n",
    "            return FALSE;\n",
    "\n",
    "        retcode = pam_acct_mgmt(pamh, 0);\n",
    "        if (retcode == PAM_NEW_AUTHTOK_REQD)\n",
    "            retcode =\n",
    "                pam_chauthtok(pamh, PAM_CHANGE_EXPIRED_AUTHTOK);\n",
    "        if (pam_fail_check(pamh, retcode))\n",
    "            return FALSE;\n",
    "\n",
    "        retcode = pam_setcred(pamh, 0);\n",
    "        if (pam_fail_check(pamh, retcode))\n",
    "            return FALSE;\n",
    "\n",
    "        pam_end(pamh, 0);\n",
    "        /* no need to establish a session; this isn't a\n",
    "         * session-oriented activity...  */\n",
    "    }\n",
    "    return TRUE;\n",
    "}\n",
    "```\n",
    "\n",
    "This is the login code for the Linux OS. Note that if we could skip the check of `if (uid != 0)` and simply branch to the end, we could avoid having to enter a password. This is the power of glitch attacks - not that we are breaking encryption, but simply bypassing the entire authentication module! \n",
    "\n",
    "### Glitch Hardware\n",
    "\n",
    "The ChipWhisperer Nano's glitch setup is pretty simple. Like its bigger brothers, the Lite and the Pro, it uses a MOSFET to short the microcontroller's voltage supply to ground:\n",
    "\n",
    "![](https://wiki.newae.com/images/8/82/Glitch-vccglitcher.png)\n",
    "\n",
    "For the Nano, `Glitch In` is controlled by 2 parameters:\n",
    "\n",
    "1. `scope.glitch.ext_offset` - The glitch will be inserted roughly `8.3ns * scope.glitch.ext_offset`\n",
    "1. `scope.glitch.repeat`     - The glitch will be inserted for roughly `8.3ns * scope.glitch.repeat`\n",
    "\n",
    "During this lab, we'll be varying these parameters to see if we can get the target to mess up a calculation that it's doing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPETYPE = 'CWNANO'\n",
    "PLATFORM = 'CWNANO'\n",
    "SS_VER = 'SS_VER_2_1'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"../../Setup_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PLATFORM\" \"$SS_VER\"\n",
    "cd ../../../firmware/mcu/simpleserial-glitch\n",
    "make PLATFORM=$1 CRYPTO_TARGET=NONE SS_VER=$2 -j"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "fw_path = \"../../../firmware/mcu/simpleserial-glitch/simpleserial-glitch-{}.hex\".format(PLATFORM)\n",
    "cw.program_target(scope, prog, fw_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.io.clkout = 7.5E6\n",
    "def reboot_flush():            \n",
    "    scope.io.nrst = False\n",
    "    time.sleep(0.05)\n",
    "    scope.io.nrst = \"high_z\"\n",
    "    time.sleep(0.05)\n",
    "    #Flush garbage too\n",
    "    target.flush()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "reboot_flush()\n",
    "scope.arm()\n",
    "target.simpleserial_write(\"g\", bytearray([]))\n",
    "scope.capture()\n",
    "val = target.simpleserial_read_witherrors('r', 4, glitch_timeout=10)#For loop check\n",
    "valid = val['valid']\n",
    "if valid:\n",
    "    response = val['payload']\n",
    "    raw_serial = val['full_response']\n",
    "    error_code = val['rv']\n",
    "print(val)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc = cw.GlitchController(groups=[\"success\", \"reset\", \"normal\"], parameters=[\"repeat\", \"ext_offset\"])\n",
    "gc.display_stats()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some tips for finding good glitches:\n",
    "\n",
    "1. This is a VCC line that we're shorting, so there's going to be stuff fighting against us. If your glitch is too short, it might not have any effect\n",
    "1. Likewise, if your glitch is too long, the target will always crash. There's typically a small band where you're able to affect the target, but it won't always crash it.\n",
    "1. Be patient. Glitching can be somewhat inconsistant, so don't be discouraged if it takes a while to see some success!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.glitch_plot(plotdots={\"success\":\"+g\", \"reset\":\"xr\", \"normal\":None})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from importlib import reload\n",
    "import chipwhisperer.common.results.glitch as glitch\n",
    "from tqdm.notebook import trange\n",
    "import struct\n",
    "\n",
    "g_step = 1\n",
    "\n",
    "gc.set_global_step(g_step)\n",
    "gc.set_range(\"repeat\", 1, 10)\n",
    "gc.set_range(\"ext_offset\", 1, 500)\n",
    "scope.glitch.repeat = 0\n",
    "\n",
    "reboot_flush()\n",
    "sample_size = 1\n",
    "for glitch_setting in gc.glitch_values():\n",
    "    scope.glitch.repeat = glitch_setting[0]\n",
    "    scope.glitch.ext_offset = glitch_setting[1]\n",
    "    successes = 0\n",
    "    resets = 0\n",
    "    for i in range(3):\n",
    "        target.flush()\n",
    "            \n",
    "        scope.arm()\n",
    "        \n",
    "        #Do glitch loop\n",
    "        target.simpleserial_write(\"g\", bytearray([]))\n",
    "        \n",
    "        ret = scope.capture()\n",
    "        \n",
    "        val = target.simpleserial_read_witherrors('r', 4, glitch_timeout=10)#For loop check\n",
    "        \n",
    "        if ret:\n",
    "            print('Timeout - no trigger')\n",
    "            gc.add(\"reset\")\n",
    "            resets += 1\n",
    "\n",
    "            #Device is slow to boot?\n",
    "            reboot_flush()\n",
    "\n",
    "        else:\n",
    "            if val['valid'] is False:\n",
    "                reboot_flush()\n",
    "                gc.add(\"reset\")\n",
    "                resets += 1\n",
    "            else:\n",
    "                gcnt = struct.unpack(\"<I\", val['payload'])[0]\n",
    "                \n",
    "                if gcnt != 2500: #for loop check\n",
    "                    gc.add(\"success\")\n",
    "                    print(gcnt)\n",
    "                    successes += 1\n",
    "                else:\n",
    "                    gc.add(\"normal\")\n",
    "    if successes > 0:                \n",
    "        print(\"successes = {}, resets = {}, repeat = {}, ext_offset = {}\".format(successes, resets, scope.glitch.repeat, scope.glitch.ext_offset))\n",
    "print(\"Done glitching\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "gc.plot_2d(alpha=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.dis()\n",
    "target.dis()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Unlike the other ChipWhisperers, the Nano doesn't have sychronous glitching. This means that `ext_offset` is a mixture of both the offset within the clock cycle, which affects glitch success, and ext_offset, which affects which instruction is being glitched. As such, ext_offset settings you find in this lab won't be directly applicable to other labs. That being said, good ranges for repeat and the success rate of glitches still gives valuable information that you can apply to other labs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
